<template>
  <div class="inline-notes-pane" id="inline-notes-wrapper">
    <div class="inline-note-wrapper" :class="noteClass(n)" v-for="(n, i) in notes" :key="i" :style="posStyle(n)">
      <div class="inline-note" v-if="n.section==NoteSection.Note" :title="n.content">
      </div>
      <div class="inline-note" v-else-if="n.section==NoteSection.Phonetics">
        <span class="pinyin">{{n.content}}</span>
      </div>
      <div class="inline-note" v-else>
      </div>
    </div>
  </div>
</template>

<script>
import { NoteKind, NoteScope, NoteSection } from "@js/constants.js";
import Vue from "vue";
import InlineNote from "../notes/InlineNote.vue";
const InlineNoteBox = Vue.extend(InlineNote);
export default {
  props: ["mat"],
  data() {
    return {
      NoteSection: NoteSection,
      notes: [], 
      lineSpans: new Map(),
      positions: new Map(),
    };
  },
  created() {
    this.loadInlineNotes();
    window.onresize = (ev) => {
      console.log(ev);
      this.calcPositions();
      this.$forceUpdate(); // TODO: 需要找到更好的更新位置手段
    };
  },
  mounted() {
    this.findLineSpans();
  },
  computed: {},
  methods: {
    findLineSpans() {
      if (this.lineSpans.size == 0) {
        let lineSpans = Array.from(this.$parent.$el.getElementsByClassName("line"));
        for (let lineSpan of lineSpans) {
          let line = Number(lineSpan.getAttribute("linenum"));
          this.lineSpans.set(line, lineSpan)
        }
      }
    },
    loadInlineNotes() {
      let mid = this.$route.params.mid;
      this.authGet("/api/v1/notes/list/mine?mid=" + mid)
        .then((res) => {
          let notes = res.data;
          let wordNotes = notes.filter(
            (n) => n.scope == NoteScope.Word || n.scope == NoteScope.Char
          );
          this.notes = wordNotes;
          this.markWords();
        })
        .catch((e) => console.log(e));
    },
    markWords() {
      console.log("words to mark:", this.notes);
      // 获取所有笔记的定位
      for (let n of this.notes) {
        let s = n.s;
        let e = n.e;
        console.log("s: ", s, "e: ", e);

        let sr = this.getRects(s, e);
        this.updatePositions(n, sr);
      }

      // 按照所在行重新组织笔记
      // let lines = new Map();
      // for (let n of notes) {
      //   let ln = n.line;
      //   if (lines.has(ln)) {
      //     lines.get(ln).push(n);
      //   } else {
      //     lines.set(ln, [n]);
      //   }
      // }
      // console.log("lines:", lines);
      // for (let ln of lines.keys()) {
      //   let ns = lines.get(ln);
      //   ns.sort((a, b) => a.spos - b.spos);
      //   console.log("marking line: ", ln);
      //   // let lineSpan = this.getLineSpan(ln)
      //   // this.markWordsInLine(ns, lineSpan);
      // }
    },
    // 把词语级别的笔记标注到文本中
    updatePositions(note, rects) {
      let rect = rects[0]; // TODO: 出现跨行时，会有多个rect，此时需要处理所有rect
      let nid = note.id;
      let pos = {
        top: rect.top,
        left: rect.left,
        width: rect.width,
        height: rect.height,
      };
      console.log("setting position:", JSON.stringify(pos));
      this.positions.set(nid, pos);
      // let wrapper = document.getElementById("inline-notes-wrapper");
      // let noteDiv = document.createElement("div");
      // noteDiv.style.position = "absolute";
      // noteDiv.style.top = rect.top + "px";
      // noteDiv.style.left = rect.left + "px";
      // noteDiv.style.width = rect.width + "px";
      // noteDiv.style.height = rect.height + "px";
      // noteDiv.classList.add("inline-note");
      // wrapper.append(noteDiv);
    },
    // 将同一行的笔记标注到该行文本中
    markWordsInLine(notes, lineSpan) {
      // 相同起始位置的笔记组织到一起
      let words = new Map();
      for (let n of notes) {
        let p = n.spos;
        if (words.has(p)) {
          words.get(p).push(n);
        } else {
          words.set(p, [n]);
        }
      }
      console.log("words:", words);
      let text = lineSpan.textContent;
      let s = 0;
      let rs = [];
      // 注意，同一行的笔记互相之间不能交叉。TODO：支持交叉、嵌套的字词笔记
      for (let p of words.keys()) {
        if (s < p) {
          // 纯字符
          rs.push({ kind: "T", text: text.substr(s, p - s) }); // 文本
        }
        let rnote = { kind: "N" };
        let spos = p;
        let epos = p;
        for (let n of words.get(p)) {
          spos = n.spos;
          epos = n.epos;
          if (n.kind == NoteKind.Phonetics) {
            rnote.pinyin = n.content; // 拼音
          } else if (n.kind == NoteKind.Note) {
            rnote.note = n.content; // 笔记、释义等
          } else if (n.kind == NoteKind.Lecture) {
            rnote.lecture = n.content; // 笔记、释义等
          }
          rnote.text = text.substr(spos, epos - spos);
        }
        rs.push(rnote);
        s = epos;
      }
      console.log("current s: ", s);
      console.log("rs: ", rs);
      if (s < text.length) {
        rs.push({ kind: "T", text: text.substr(s) }); // 将最后的文本补齐
      }
      // 备份原始文本
      lineSpan.origText = text;

      // 清空本行的内容，替换为笔记标注
      lineSpan.innerHTML = "";
      for (let r of rs) {
        if (r.kind == "T") {
          let d = document.createTextNode(r.text);
          lineSpan.appendChild(d);
        } else if (r.kind == "N") {
          let box = new InlineNoteBox({
            parent: this,
            propsData: {
              word: r,
            },
          });
          lineSpan.appendChild(box.$mount().$el);
        }
      }
    },
    getLineSpan(line) {
      this.findLineSpans();
      return this.lineSpans.get(line);
    },
    getTextNode(line, pos) {
      let lineSpan = this.getLineSpan(line);
      console.log("node pos:", pos);
      let node = lineSpan.childNodes[0]; // 如果lineSpan中还有其他子节点，这里就没法取到正确的node了。需要更精细的定位
      return node;
    },
    getRects(s, e) {
      let r = document.createRange();

      let snode = this.getTextNode(s.line, s.pos);
      r.setStart(snode, s.pos);

      let enode = this.getTextNode(e.line, e.pos);
      r.setEnd(enode, e.pos);
      return r.getClientRects();
    },
    calcPositions() {
      for (let n of this.notes) {
        let rects = this.getRects(n.s, n.e);
        this.updatePositions(n, rects);
      }
    },
    noteClass(n) {
      return "note-section-"+n.section;
    },
    posStyle(n) {
      let pos = this.positions.get(n.id);
      console.log("pos:", pos)
      return `top:${pos.top}px;left:${pos.left}px;width:${pos.width}px;height:${pos.height}.px`;
    },
  },
};
</script>

<style lang="stylus">
#inline-notes-wrapper
  position absolute
  pointer-events none
  top 0
  left 0

  .inline-note-wrapper
    position absolute
    background transparent
    padding 0

    .inline-note
      background transparent
      height 100%
      width 100%


    &.note-section-1
      z-index 5
      border-bottom 2px solid teal

    &.note-section-2
      z-index 4 
      border-bottom 2px solid #999
      .pinyin
        position absolute
        bottom 100%
        width 100%
        left 0
        text-align center
        font-size 0.8em
        color #999

</style>